package com.hns.frame.mybatis;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import com.hns.can.base.entity.SysAuthrityFieldValueEntity;
import com.hns.can.base.entity.SysUserEntity;
import com.hns.can.common.constants.SysCache;
import com.hns.frame.security.AppUserDetailsImpl;
import com.hns.tool.pub.DataConvertUtil;
import com.hns.tool.pub.PubUtil;

/**
 * @版权：HNS 版权所有 (c) 2013
 * @author:Fisher
 * @version Revision 1.0.0
 * @email:zhuangcaijin@126.com
 * @see:
 * @创建日期：2014-4-10
 * @功能说明：mybatis 分页拦截器
 * @begin
 * @修改记录:
 * @修改后版本          修改人      	修改内容
 * @2014-4-10  	         Fisher        	创建
 * @end
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class }) })
public class PaginationInterceptor implements Interceptor {
    private Logger logger = LoggerFactory.getLogger(getClass());
    private Pattern p = Pattern.compile("(\\w*\\.)?(?i)CORP_ID ?= ?\\?");
    
    /**
     * {@inheritDoc}
     * @see org.apache.ibatis.plugin.Interceptor#intercept(org.apache.ibatis.plugin.Invocation)
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     * @创建日期:2014-5-12
     * @功能说明：
     */
    @SuppressWarnings("rawtypes")
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
    	StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaStatementHandler = MetaObject.forObject(statementHandler);
        
    	/**
         * 增加资源受控模块 2015-01-23
         */
        processAuthResource(statementHandler, metaStatementHandler);
        
        Map parameterMap = DataConvertUtil.ConvertObjToMap(metaStatementHandler.getValue("delegate.rowBounds"));
        if(String.valueOf(RowBounds.NO_ROW_LIMIT).equals(parameterMap.get("limit").toString()) 
            && String.valueOf(RowBounds.NO_ROW_OFFSET).equals(parameterMap.get("offset").toString())){
            return invocation.proceed(); 
        }
        
        RowBoundsExt rowBounds = (RowBoundsExt)metaStatementHandler.getValue("delegate.rowBounds");
        if(rowBounds == null){    
            return invocation.proceed();  
        }
        //DefaultParameterHandler defaultParameterHandler = (DefaultParameterHandler)metaStatementHandler.getValue("delegate.parameterHandler");
        //Map parameterMap = DataConvertUtil.ConvertObjToMap(defaultParameterHandler.getParameterObject());
        Object objSidx = parameterMap.get("sidx");
        Object objSord = parameterMap.get("sord");
        String sidx = objSidx != null ? objSidx.toString() : "";
        String sord = objSord != null ? objSord.toString() : "";
        String originalSql = (String)metaStatementHandler.getValue("delegate.boundSql.sql");
        if(PubUtil.isNotEmpty(sidx) && PubUtil.isNotEmpty(sord)){    
            originalSql = originalSql + " order by " + sidx + " " + sord;    
        }
        Configuration configuration = (Configuration)metaStatementHandler.getValue("delegate.configuration");
        DialectType databaseType  = null;
        try{    
            databaseType = DialectType.valueOf(configuration.getVariables().getProperty("dialect").toUpperCase());    
        } catch(Exception e){    
            e.printStackTrace();
        }
        if(databaseType == null){    
            throw new RuntimeException("the value of the dialect property in configuration.xml is not defined : " + configuration.getVariables().getProperty("dialect"));    
        }
        Dialect dialect = null;    
        switch(databaseType){    
            case ORACLE:    
                dialect = new OracleDialect();    
                break;    
            case MYSQL://需要实现MySQL的分页逻辑
                dialect = new MysqlDialect();
                break;    
        }
        metaStatementHandler.setValue("delegate.boundSql.sql", dialect.getLimitString(originalSql,true, (rowBounds.getPageNumber()-1)*rowBounds.getLimit(), rowBounds.getLimit()) );    
        metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET );    
        metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT );      
        if(logger.isDebugEnabled()){    
            BoundSql boundSql = statementHandler.getBoundSql();    
            logger.debug("生成分页SQL : " + boundSql.getSql());    
        }
        return invocation.proceed(); 
    }
    
    private void processAuthResource(StatementHandler statementHandler, MetaObject metaStatementHandler) throws Exception {
    	BoundSql boundSql = statementHandler.getBoundSql();
    	String sql = boundSql.getSql();
    	
    	// 系统管理员查看所有数据，去除corp_id过滤条件
    	Matcher m = p.matcher(sql);
        if(m.find()) {
        	String corpIdValue = "";
        	if(boundSql.getParameterObject() instanceof String) {
        		corpIdValue = (String)boundSql.getParameterObject();
        	} else if(boundSql.getParameterObject() instanceof HashMap) {
        		HashMap<String, Object> paramObjMap = (HashMap)boundSql.getParameterObject();
        		corpIdValue = (String)paramObjMap.get("corpId");
        	} else {
        		Class cl = boundSql.getParameterObject().getClass();
        		Method method = cl.getMethod("getCorpId");
        		corpIdValue = (String)method.invoke(boundSql.getParameterObject());
        	}
        	if("39708c61759b48748c5bd853ba64ded5".equals(corpIdValue)) {
        		sql = m.replaceAll("'39708c61759b48748c5bd853ba64ded5' = ?");
        	}
        	metaStatementHandler.setValue("delegate.boundSql.sql", sql);
        }
        
        // 取得登录用户信息
        Authentication authentication = SecurityContextHolder.getContextHolderStrategy().getContext().getAuthentication();
    	if(authentication == null || "anonymousUser".equals(authentication.getPrincipal())) {
    		return;
    	}
    	AppUserDetailsImpl userImpl = (AppUserDetailsImpl)authentication.getPrincipal();
    	SysUserEntity currentUser = userImpl.getUser();
    	
    	// 获取用户对应的资源字段值
    	List<SysAuthrityFieldValueEntity> authList = SysCache.getAuthrityFieldValue(currentUser.getId());
    	if(PubUtil.isEmpty(authList)) {
    		return;
    	}
    	
    	sql = (String)metaStatementHandler.getValue("delegate.boundSql.sql");
//    	Map<String, ArrayList<String>> tableMap = new HashMap<String, ArrayList<String>>();
    	// Key:表名称     Value:(Key:字段名称     Value:字段值list)
    	Map<String, Map<String, ArrayList<String>>> tableMap = new HashMap<String, Map<String, ArrayList<String>>>();
    	for(int i = 0; i < authList.size(); i++) {
//    		String value = authList.get(i).getFieldName() + "='" + authList.get(i).getFieldCodeValue() + "'";
    		
    		String[] tableArray = authList.get(i).getTableName().split(",");
    		String[] fieldArray = authList.get(i).getFieldName().split(",");
    		
    		for(int j = 0; j < tableArray.length; j++) {
    			if(!tableMap.containsKey(tableArray[j])) {
    				Map<String, ArrayList<String>> fieldMap = new HashMap<String, ArrayList<String>>();
    				
    				ArrayList<String> valueList = new ArrayList<String>();
    				valueList.add(authList.get(i).getFieldCodeValue());
    				fieldMap.put(fieldArray[j], valueList);
    				tableMap.put(tableArray[j], fieldMap);
    			} else {
    				ArrayList<String> valueList = tableMap.get(tableArray[j]).get(fieldArray[j]);
    				valueList.add(authList.get(i).getFieldCodeValue());
    			}
    		}
//    		if(!tableMap.containsKey(authList.get(i).getTableName())) {
//    			ArrayList<String> valueList = new ArrayList<String>();
//    			valueList.add(value);
//    			tableMap.put(authList.get(i).getTableName(), valueList);
//    		} else {
//    			ArrayList<String> valueList = tableMap.get(authList.get(0).getTableName());
//    			valueList.add(value);
//    		}
    	}
    	
    	// 组装新SQL
    	for(String tableName : tableMap.keySet()) {
    		if(sql.contains(tableName)) {
    			String condition = " WHERE 1=1 ";
    			String conditionTmp = "";
                for (String fieldName : tableMap.get(tableName).keySet()) {
                    ArrayList<String> valueList = tableMap.get(tableName).get(fieldName);
                    // upt by jeffxu
                    String values = "'-',";
                    String value = "";
                    for (int i = 0; i < valueList.size(); i++) {
                        value = valueList.get(i);
                        if (!"-".equals(value)) {
                            values = values + value + ",";
                        }
                    }
                    values = values.substring(0, values.lastIndexOf(","));
                    
                    conditionTmp = conditionTmp + " AND " + fieldName + " IN(" + values + ") ";
                }
                condition = condition + conditionTmp;
//    			ArrayList<String> valueList = tableMap.get(tableName);
//    			for(String value : valueList) {
//    				condition = condition + value + " OR ";
//    			}
//    			condition = condition.substring(0, condition.lastIndexOf(" OR "));
    			
    			logger.info(">>>>>>>>>>>>>>>>>>>>>>>>SQL替换前");
    			logger.info(sql);
    			sql = sql.replaceAll("\\b"+tableName+"\\b", "(SELECT * FROM " + tableName + condition + ")");
    			logger.info(">>>>>>>>>>>>>>>>>>>>>>>>SQL替换后");
    			logger.info(sql);
    			
    			metaStatementHandler.setValue("delegate.boundSql.sql", sql);
    		}
    	}
    }

    /**
     * {@inheritDoc}
     * @see org.apache.ibatis.plugin.Interceptor#plugin(java.lang.Object)
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     * @创建日期:2014-5-12
     * @功能说明：
     */
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    
    /**
     * {@inheritDoc}
     * @see org.apache.ibatis.plugin.Interceptor#setProperties(java.util.Properties)
     * @author:Fisher
     * @email:zhuangcaijin@126.com
     * @创建日期:2014-5-12
     * @功能说明：
     */
    @Override
    public void setProperties(Properties arg0) {
        // TODO Auto-generated method stub
    }
    
}
